package schoolmath.web.components.content;

import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.tapestry5.SelectModel;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.InjectComponent;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.corelib.components.Form;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import schoolmath.web.entities.Presentation;
import schoolmath.web.entities.UserGroup;
import schoolmath.web.services.SelectService;
import schoolmath.web.services.UserService;
import schoolmath.web.services.valueEncoders.PresentationEncoder;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


@RequiresRoles(value = {"Администратор", "Преподаватель"}, logical = Logical.OR)
public class ManagePresentationsContent {

	private static Logger logger = LoggerFactory.getLogger(ManagePresentationsContent.class);
	private List<Presentation> presentations;
	private Presentation presentation;
	@Inject
	private Session session;
	@Component
	private Form presentationsEdit;
	@Inject
	private UserService userService;
	@Component
	private Zone presentationsEditZone;
	private List<Presentation> deletedPresentations = new ArrayList<>();
	private boolean inFormSubmission;
	private List<Presentation> presentationsSubmitted;
	@Property
	@Inject
	private PresentationEncoder presentationEncoder;
	private boolean editing;
	@InjectComponent
	private Zone rowZone;
	private List<UserGroup> userGroups;
	private SelectModel userGroupsSelectModel;
	@Inject
	private SelectService selectService;

	public boolean getCreating() {
		return this.presentation.getId() == null;
	}

	public boolean getChanging() {
		return editing || this.presentation.getId() == null;
	}

	public String getChangingId() {
		if (editing) {
			return presentation.getId().toString();
		} else {
			return "";
		}
	}

	@SuppressWarnings("unchecked")
	public List<UserGroup> getUserGroups() {
		if (userGroups == null) {
			userGroups = session.createCriteria(UserGroup.class)
					.add(Restrictions.eq("owner", userService.getUser())).list();
		}
		return userGroups;
	}

	public SelectModel getUserGroupsSelectModel() {
		if (userGroupsSelectModel == null) {
			userGroupsSelectModel = selectService
					.createSelectModel(selectService.createOptionModelList(getUserGroups()));
		}
		return userGroupsSelectModel;
	}

	public Presentation getPresentation() {
		return this.presentation;
	}

	public void setPresentation(Presentation presentation) {
		this.presentation = presentation;

		if (inFormSubmission) {
			presentationsSubmitted.add(presentation);
		}
	}

	public void onActivate() {
		inFormSubmission = false;
	}

	public Presentation onAddRow() {
		return new Presentation(userService.getUser(), "");
	}

	public void onRemoveRow(Presentation presentation) {
		deletedPresentations.add(presentation);
	}

	@SuppressWarnings("unchecked")
	public List<Presentation> getPresentations() {
		if (presentations == null) {
			presentations = session.createCriteria(Presentation.class)
					.add(Restrictions.eq("owner", userService.getUser()))
					.addOrder(org.hibernate.criterion.Order.asc("id")).list();
		}
		return presentations;
	}

	private void delete() {
		for (Presentation presentation : deletedPresentations) {
			deletedPresentations.remove(presentation);
		}
	}

	@CommitAfter
	private void save() {
		for (Presentation presentation : deletedPresentations) {
			if (presentation.getId() != null) {
				session.delete(presentation);
			}
		}
		for (Presentation presentation : presentationsSubmitted) {
			if (presentation.getId() != null) {
				session.update(presentation);
			} else {
				session.merge(presentation);
			}
		}
	}

	public void onPrepareForSubmit() {
		inFormSubmission = true;
		presentationsSubmitted = new ArrayList<>();
	}

	public void onValidateFromPresentationsEdit() {
		Set<String> names = new HashSet<>();
		for (Presentation presentation : presentationsSubmitted) {
			if (names.contains(presentation.getName())) {
				presentationsEdit.recordError("Имеются повторяющиеся названия презентаций");
				return;
			}
			names.add(presentation.getName());
		}
	}

	public Object onSuccess() {
		delete();
		save();
		presentations = null;
		return presentationsEditZone.getBody();
	}

	public Object onFailure() {
		presentations = new ArrayList<>(presentationsSubmitted);
		return presentationsEditZone.getBody();
	}

	public Object onRefresh() {
		presentationsEdit.clearErrors();
		presentations = null;
		return presentationsEditZone.getBody();
	}

	public Object onEdit(Presentation presentation) {
		this.presentation = presentation;
		editing = true;
		return rowZone.getBody();
	}

	public Object onCancel(Presentation presentation) {
		this.presentation = presentation;
		return rowZone.getBody();
	}

	public Object onRefreshPage() {
		return this;
	}

	@CommitAfter
	private void start(Presentation presentation) {
		presentation.setPlaying(true);
		session.save(presentation);
	}

	@CommitAfter
	private void stop(Presentation presentation) {
		presentation.setPlaying(false);
		presentation.setCurrentUserGroup(null);
		session.save(presentation);
	}

	public Object onStart(Presentation presentation) {
		this.presentation = presentation;
		start(presentation);
		return rowZone.getBody();
	}

	public Object onStop(Presentation presentation) {
		this.presentation = presentation;
		stop(presentation);
		return rowZone.getBody();
	}

	public Boolean getCanPlay() {
		return !presentation.getPlaying() && presentation.getCurrentUserGroup() != null;
	}

}
